﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace Kaleta.Xna
{
    public class KeyboardInput
    {
        private KeyboardState oldState;
        private IDictionary<Keys, double> keyPressTimes = new Dictionary<Keys, double>();
        private IDictionary<Keys, KeyState> trackKeys = new Dictionary<Keys, KeyState>();
        public const float DoublePressedDelay = 300f;

        public KeyboardInput(KeyboardState initState)
        {
            oldState = initState;
        }

        public KeyboardInput(KeyboardState initState, params Keys[] keysToTrack)
        {
            oldState = initState;
            foreach (var key in keysToTrack)
                trackKeys.Add(key, KeyState.Up);
        }

        public void Track(Keys key)
        {
            trackKeys.Add(key, KeyState.Up);
        }

        public void RemoveTrack(Keys key)
        {
            trackKeys.Remove(key);
        }

        public void Update(KeyboardState newState, GameTime gameTime)
        {
            //int count = trackKeys.Keys.Count;

            foreach (var key in trackKeys.Keys.ToArray())
            {

                if (newState.IsKeyDown(key))
                {
                    trackKeys[key] &= ~KeyState.Up;
                    trackKeys[key] &= ~KeyState.Pressed;
                    trackKeys[key] &= ~KeyState.DoublePressed;
                    trackKeys[key] &= ~KeyState.Released;

                    trackKeys[key] |= KeyState.Down;

                    if (!oldState.IsKeyDown(key))
                    {
                        //is just pressed

                        trackKeys[key] |= KeyState.Pressed;

                        if (keyPressTimes.ContainsKey(key) && gameTime.TotalGameTime.TotalMilliseconds - keyPressTimes[key] < DoublePressedDelay)
                        {
                            //is double pressed within delay
                            trackKeys[key] |= KeyState.DoublePressed;

                        }
                        else
                            keyPressTimes[key] = gameTime.TotalGameTime.TotalMilliseconds;

                    }
                }
                else if (oldState.IsKeyDown(key))
                {
                    //was just released

                    trackKeys[key] &= ~KeyState.Pressed;
                    trackKeys[key] &= ~KeyState.DoublePressed;
                    trackKeys[key] &= ~KeyState.Down;

                    trackKeys[key] |= KeyState.Released | KeyState.Up;
                }
                else
                {
                    trackKeys[key] &= ~KeyState.Pressed;
                    trackKeys[key] &= ~KeyState.DoublePressed;
                    trackKeys[key] &= ~KeyState.Down;
                    trackKeys[key] &= ~KeyState.Released;

                    trackKeys[key] |= KeyState.Up;
                }

            }
            oldState = newState;
        }

        public bool IsDown(Keys key)
        {
            return (trackKeys[key] & KeyState.Down) == KeyState.Down;
        }

        public bool IsPressed(Keys key)
        {
            return (trackKeys[key] & KeyState.Pressed) == KeyState.Pressed;
        }

        public bool IsDoublePressed(Keys key)
        {
            return (trackKeys[key] & KeyState.DoublePressed) == KeyState.DoublePressed;
        }

        public bool IsReleased(Keys key)
        {
            return (trackKeys[key] & KeyState.Released) == KeyState.Released;
        }

        public bool IsUp(Keys key)
        {
            return (trackKeys[key] & KeyState.Up) == KeyState.Up;
        }
    }

    [Flags]
    public enum KeyState { Up = 1, Pressed = 2, DoublePressed = 4, Released = 8, Down = 16, }
}
